Ruby入门
Ruby简介
Ruby 是脚本语言,由日本人松本行弘编写。这个语言最大的特点就是"对程序员友好". 用Martin Fowler等人的话说,就是"我在任何时候手头都要带着它(Ruby锄头书)"
如果你接触过C/C++, java, object C等语言,回过头再看Ruby,就会发现它特别简洁,代码极度好懂.
Ruby支持Linux, Mac, 以及Windows. 但是我们只在Linux 和Mac下工作,Windows我们就不考虑了.
下面都假设你在Linux下(大部分情况适用于Mac)
安装Ruby
虽然系统默认自带了Ruby,但是不如我们自定义的灵活.我们使用rbenv 来安装Ruby, 最大的好处是 可以允许你同时安装多个Ruby版本.
安装rbenv
rbenv(ruby environment),是管理多个不同版本的ruby工具,是之前rvm(ruby version manager)的替代品。类似的工具还有管理不同Node版本的nvm(node version manager)。
具体的安装步骤为:
git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
# 用来编译安装 ruby
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
# 用来管理 gemset, 可选, 因为有 bundler 也没什么必要
git clone git://github.com/jamis/rbenv-gemset.git ~/.rbenv/plugins/rbenv-gemset
# 通过 gem 命令安装完 gem 后无需手动输入 rbenv rehash 命令, 推荐
git clone git://github.com/sstephenson/rbenv-gem-rehash.git ~/.rbenv/plugins/rbenv-gem-rehash
# 通过 rbenv update 命令来更新 rbenv 以及所有插件, 推荐
git clone https://github.com/rkh/rbenv-update.git ~/.rbenv/plugins/rbenv-update
然后把下面的代码放在~/.zshrc里面
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
注意 :如果你使用的是bash,那应该把上面的代码放在~/.bashrc或者~/.bash_profile里面
最后,重启一下你的Terminal就OK了。
安装ruby
rbenv install --list # 列出所有可以安装的ruby版本
rbenv install 1.9.3-p551 # 安装特定版本的ruby
注意 :使用rbenv安装了ruby之后,要指定你想要使用的本班为当前版本
rbenv global 1.9.3-p551 # 指定版本
列出ruby版本
rbenv versions # 系统所有通过rbenv安装的ruby版本
rbenv version # 当前版本
调试方法: irb
irb = interactive ruby
在命令行下,输入 $ irb
即可. 这是一个ruby的即时调试界面.
几点说明
用 # =>
表示输出结果 , 例如:
puts "goodbye java"
# => "goodbye java"
用$, 或者# 表示bash命令行程序,例如:
$ ruby test_my_module.rb
或者:
# ps -ef | grep nginx
Hello World
新建一个文件
# hello.rb:
puts 'Hello world!'
运行,就会看到效果:
$ ruby hello.rb
赋值
name = "jim"
# => jim
字符串插值
在Ruby中,我们最好所有的地方都用字符串插值(interpolition) ,避免使用 + 方式. 原因是:对于不同的数据类型,用+号时,系统会报错.
使用字符串插值时,记得用双引号.
name = "jim"
puts "hi, #{name}!"
# => hi, jim
你也可以把它写成:
puts "hi, "+ name
# => hi, jim
如果用加号,一些时候就会报错:
a = 1
puts "a is: " + a
# => 报错
puts "a is: #{a}"
# => a is: 1
任何语言都通用的 数据类型.
- String 字符串 "abc"
- Number (包括了: 整数,小数,long double ...) 数字, 123342342342343.3141234
- Array. 数组 [1,2,3]
- Hash hash. (dictionary)
{
"name": "dashi",
"birth": "1982-9-16"
}
对象和实例 .
对象: class, object 抽象概念, 例如: human
实例: instance. 具体概念. 小王.
小王 是 Human 的一个 instance.
小王有个属性,叫做: "名字", 那么,小王的名字,就可以认为,是 instance varaible. (实例变量, 只跟实例有关)
双引号与单引号
class
我们从一个例子来看, 注意代码中的注释:
class Apple
# 这个方法就是在 Apple.new 时自动调用的方法
def initialize
# instance variable, 实例变量
@color
end
# getter 方法
def color
return @color
end
# setter 方法
def color= color
@color = color
end
# private 下面的方法都是私有方法
private
def i_am_private
end
end
red_apple = Apple.new
red_apple.color = 'red'
puts "red_apple.color: #{red_apple.color}"
我们来运行这个文件:
$ ruby apple.rb
# => "red_apple.color: red"
上面的例子是java/c风格的. ruby的熟手一般这么写:
class Apple
# 这一句,自动声明了 @color, getter,setter
attr_accessor 'color'
end
变量
类变量: class variable, 例如: @@name
, 作用域:所有的多个instance 会共享这个变量. 用的很少.
实例变量 instance variable, 例如: @color
, 作用域仅在instance之内
普通变量: local variable, 例如: age = 20
, 作用域仅在 某个方法内.
全局变量: global variable, 例如:$name = "Jim"
, 作用域在全局. 用的更少.
下面是一个例子:
class Apple
@@from = 'China'
def color= color
@color = color
end
def color
return @color
end
def get_from
@@from
end
def set_from from
@@from = from
end
end
red_one = Apple.new
red_one.color = 'red'
puts red_one.color
# => 'red'
red_one.set_from 'Japan'
puts red_one.get_from
# => 'Japan'
green_one = Apple.new
green_one.color = 'green'
puts green_one.color
# => 'green'
puts green_one.get_from
# => 'Japan'
方法:类方法(class method)与实例方法(instance method)
用法上, 看这个例子:
class Apple
# 类方法
def Apple.name
'apple'
end
# 实例方法
def color
'red'
end
end
Apple.new.color
# => red
Apple.name
# => apple
Symbol
前面的apple.rb例子中, 正常的应该写成:
class Apple
attr_accessor :color
end
这个 :color 是什么呢? 就是Symbol. 它是不会变化的字符串. TODO 具体的学术概念
:name 等同于: "name".to_symbol
hash
# 任何情况下都生效的语法: =>
jim = {
:name => 'Jim',
:age => 20
}
# Ruby 1.9之后产生的语法:更加简洁.
jim = {
name: 'Jim',
age: 20
}
# 也可以写成:
jim = {}
jim[:name] = 'Jim'
jim[:age] = 20
但是, symbol 与 string , 是不同的key, 例如:
a = {:name => 'jim', 'name'=> 'hi'}
a[:name] #=> 'jim'
a['name'] #=> 'hi'
ruby中的简写
初学者看到Ruby中的简写,立马蒙圈了.
give "我", :what => '咖啡', :count => '2', :unit => '杯' do
"味道不错哟!"
end
上面的代码, 会让没有接触过ruby的同学不明就里. 我就问一个问题:
give 函数有几个参数?
每个函数的最后一行默认是返回值,是不需要写return的,例如:
def color
'red' # 等同于: return 'red'
end
方法调用的最外面的大括号可以省略。例如:
puts "hihihi" # 等同于 puts("hihihi")
hash最外面的{} 在大多数情况下可以省略,例如:
具体的省略:
如果这个 hash, 是某方法的最后一个参数(不考虑block的话),那么最外层{} 可以省略
Apple.create :name => 'apple', :color => 'red'
#等同于:
Apple.create({:name => 'apple', :color => 'red'})
#等同于hash的另一种写法: Apple.create name: 'apple', color: 'red'
调用某个block中的某个方法:
Apple.all.each do { |apple| apple.name }
# 等同于:
Apple.all.map(&:name)
条件语句
if else end 是最常见的
a = 1
if a == 1
puts "a is 1"
elsif a == 2
puts "a is 2"
else
puts "a is not in [1,2]"
end
case when end 分支语句
例如:
a = 1
case a
when 1 then puts "a is 1"
when 2 then puts "a is 2"
when 3,4,5 then puts "a is in [3,4,5]"
else puts "a is not in [1,2,3,4,5]"
end
三元表达式
a = 1
puts a == 1 ? 'one' : 'not one'
# => one
也可以写成:
for, each, loop, while 循环
for 与each 几乎一样.例如:
[1,2,3].each { |e|
puts e
}
# 等同于下方:
for e in [1,2,3]
puts e
end
for 与 each 都可以做循环,但是高手都用each. 区别在于:for 是关键字, each是方法. for 后面的变量,是全局变量,不仅仅存在于for .. end 这个作用域之内.(具体见这个stackoverflow 上的问题: for vs each.)[http://stackoverflow.com/questions/3294509/for-vs-each-in-ruby])
举个例子:
for i in [1,2,3]
puts i
end
puts i # => 3
loop与while是几乎一样的.
loop do
# your code
break if <condition>
end
begin
# your code
end while <condition>
但是ruby的作者推荐使用loop. 因为可读性更强. 下面是一个例子:
a = [2,1,0,-1,-2]
loop do
current_element = a.pop
puts current_element
break if current_element < 0
end
# => 2
# => 1
# => 0
命名规则
常量: 全都是大写字母.ANDROID_SYSTEM = 'android'
变量:如果不算@, @@, $的话,是小写字母开头.下划线拼接.例如: color
, age
, is_created
class, module: 首字母大写,骆驼表达法: Apple, Human
方法名: 小写字母开头. 可以以问号? 或者等号结尾,例如: name
, created?
, color=
查看API
查看ruby API 很其他的语言差不多.官方文档是:api.ruby-lang.org? TODO 详细图文
ruby DEBUG 之调试信息
- ruby的出错信息, 距离顺序是从上到下,时间顺序是从下到上,出现的.例如:
test_class.rb:8:in `extend': wrong argument type Class (expected Module) (TypeError)
from test_class.rb:8:in `<class:Child>'
from test_class.rb:7:in `<main>'
上面信息中,时间的运行顺序是,先运行 test_class.rb的第7行,再运行到第8行,才出错.
出错信息是 wrong argument type Class (expected Module) (TypeError)
- 在调试中,class instance 的最外层是#<> 的固定格式,前面的Apple表示class名字,0x00000001f0dad8 是内存的地址.
例如:#
:: 双冒号
表示 class的 常量 也表示 某个命名空间
class Interface
class Apple
COLOR = 'red'
end
end
puts Interface::Apple::COLOR
rails中:
app/controller/interface/apples_controller的话:
class Interface::ApplesController < ApplicationController::Base
## 其他代码
end
我们在实战中,会有这样的模式:
当访问某个页面的时候,
普通人: /pages 管理员: /admin/pages
在上面的例子中, '/admin' 就是一个非常典型的 "命名空间". 我们也可以叫它: url前缀.
它没有任何意义, 存在的目的,就是为了区别 管理员与普通用户的URL (方便权限的管理)
block, proc, lambda
几乎是一样的. 都表示代码块儿.
ruby的代码块儿是相比其他传统语言特别强大的功能. 碾压其他传统语言.
例子:
[1,2,3].each { |e| puts e }
# 假设student有两个属性:name, age
Student.all.map { |student|
{
:name => student.name,
:aget => student.age
}
}
最后一行代码默认是返回值.
block的最后一行代码是返回值.
[1,2,3].map { |e|
"#{e}#{e}" # 这里是block的最后一行,默认是被return 的.
}
# => ["11", "22", "33"]
下面这样写,会报错:
[1,2,3].map { |e|
return "#{e}#{e}"
}
# => in `block in <main>': unexpected return (LocalJumpError)
do ...end 与 { } 几乎是一样的.
可以认为下面两个代码相同
[1,2,3].each { |e|
puts e
}
[1,2,3].each do |e|
puts e
end
一个方法最多只有一个参数是 block, 并且永远是参数的最后一位.
我不会在这里详细讲解block 的定义, 但是大家在使用的时候,要知道这一点,例如:
回到 "简写" 这一节最初的问题:
give "我", :what => '咖啡', :count => '2', :unit => '杯' do
"味道不错哟!"
end
从这里,可以看出:
give(
"我", # => 第一个参数,是一个 string
{:what => '咖啡', :count => '2', :unit => '杯'}, # => 第二个参数,是个hash
do "味道不错哟!" end # => 这是第三个参数,是一个block. 也是最后一个参数
)